package io.shuttle.mbe.api

import io.shuttle.mbe.api.annotation.ChromeMinVersion
import io.shuttle.mbe.api.annotation.ChromeOSOnly
import io.shuttle.mbe.api.annotation.PromiseStyleMinVersion
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.api.types.VoidFunction
import io.shuttle.mbe.core.Promise

interface System {
    ////////////////////
    // System CPU
    ////////////////////
    /**
     * Use the `system.cpu` API to query CPU metadata.
     *
     * Permissions: "system.cpu"
     */
    interface Cpu {
        // Queries basic CPU information of the system.
        @PromiseStyleMinVersion(91)
        abstract fun getInfo(
            callback: Value1Function<CpuInfo>? = null
        ): Promise<CpuInfo>

        data class CpuInfo(
            // The architecture name of the processors.
            var archName: String,
            // A set of feature codes indicating some of the processor's capabilities. The currently supported codes are "mmx", "sse", "sse2", "sse3", "ssse3", "sse4_1", "sse4_2", and "avx".
            var features: List<String>,
            // The model name of the processors.
            var modelName: String,
            // The number of logical processors.
            var numOfProcessors: Number,
            // Information about each logical processor.
            var processors: List<ProcessorInfo>,
            // List of CPU temperature readings from each thermal zone of the CPU. Temperatures are in degrees Celsius.
            @ChromeMinVersion(60)
            var temperatures: List<Number>,
        )

        data class ProcessorUsage(
            // The cumulative time spent idle by this processor.
            var idle: Number,
            // The cumulative time used by kernel programs on this processor.
            var kernel: Number,
            // The total cumulative time for this processor. This value is equal to user + kernel + idle.
            var total: Number,
            // The cumulative time used by userspace programs on this processor.
            var user: Number,
        )

        data class ProcessorInfo(
            // Cumulative usage info for this logical processor.
            var usage: ProcessorUsage,
        )
    }
    ////////////////////
    // System Display //
    ////////////////////
    /**
     * Use the `system.display` API to query display metadata.
     *
     * Permissions: "system.display"
     */
    interface Display {

        // Resets the touch calibration for the display and brings it back to its default state by clearing any touch calibration data associated with the display.
        // @param {String} The display's unique identifier.
        @ChromeMinVersion(57)
        abstract fun clearTouchCalibration(id: String)

        // Sets the touch calibration pairs for a display. These pairs would be used to calibrate the touch screen for display with id called in startCustomTouchCalibration(). Always call startCustomTouchCalibration before calling this method. If another touch calibration is already in progress this will throw an error.
        @ChromeMinVersion(57)
        abstract fun completeCustomTouchCalibration(
            // The pairs of point used to calibrate the display.
            pairs: TouchCalibrationPairQuad,
            // Bounds of the display when the touch calibration was performed. bounds.left and bounds.top values are ignored.
            bounds: Bounds
        )

        // Enables/disables the unified desktop feature. If enabled while mirroring is active, the desktop mode will not change until mirroring is turned off. Otherwise, the desktop mode will switch to unified immediately. NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
        // @param {Boolean} True if unified desktop should be enabled.
        @ChromeMinVersion(46)
        abstract fun enableUnifiedDesktop(enabled: Boolean)

        // Requests the layout info for all displays. NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
        @ChromeMinVersion(53)
        @PromiseStyleMinVersion(91)
        abstract fun getDisplayLayout(callback: Value1Function<List<DisplayLayout>>? = null): Promise<List<DisplayLayout>>

        // Requests the information for all attached display devices.
        @PromiseStyleMinVersion(91)
        abstract fun getInfo(
            // Options affecting how the information is returned.
            flags: GetInfoFlags?,
            callback: Value1Function<List<DisplayUnitInfo>>? = null
        ): Promise<List<DisplayUnitInfo>>

        // Adjusts the current overscan insets for a display. Typically this should either move the display along an axis (e.g. left+right have the same value) or scale it along an axis (e.g. top+bottom have opposite values). Each Adjust call is cumulative with previous calls since Start.
        // @param {String} The display's unique identifier.
        // @param {Insets} he amount to change the overscan insets.
        @ChromeMinVersion(53)
        abstract fun overscanCalibrationAdjust(id: String, delta: Insets)

        // Complete overscan adjustments for a display by saving the current values and hiding the overlay.
        // @param {String} The display's unique identifier.
        @ChromeMinVersion(53)
        abstract fun overscanCalibrationComplete(id: String)

        // Resets the overscan insets for a display to the last saved value (i.e before Start was called).
        // @param {String} The display's unique identifier.
        @ChromeMinVersion(53)
        abstract fun overscanCalibrationReset(id: String)

        // Starts overscan calibration for a display. This will show an overlay on the screen indicating the current overscan insets. If overscan calibration for display id is in progress this will reset calibration.
        // @param {String} The display's unique identifier.
        @ChromeMinVersion(53)
        abstract fun overscanCalibrationStart(id: String)

        // Set the layout for all displays. Any display not included will use the default layout. If a layout would overlap or be otherwise invalid it will be adjusted to a valid layout. After layout is resolved, an onDisplayChanged event will be triggered. NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
        @ChromeMinVersion(53)
        @PromiseStyleMinVersion(91)
        abstract fun setDisplayLayout(
            // The layout information, required for all displays except the primary display.
            layouts: List<DisplayLayout>,
            callback: VoidFunction? = null
        ): Promise<Void>

        // Updates the properties for the display specified by id, according to the information provided in info. On failure, runtime.lastError will be set. NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
        @PromiseStyleMinVersion(91)
        abstract fun setDisplayProperties(
            // The display's unique identifier.
            id: String,
            // The information about display properties that should be changed. A property will be changed only if a new value for it is specified in info.
            info: DisplayProperties,
            callback: VoidFunction? = null
        ): Promise<Void>

        // Sets the display mode to the specified mirror mode. Each call resets the state from previous calls. Calling setDisplayProperties() will fail for the mirroring destination displays. NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
        @ChromeMinVersion(65)
        @PromiseStyleMinVersion(91)
        abstract fun setMirrorMode(
            // The information of the mirror mode that should be applied to the display mode.
            info: MirrorModeInfo,
            callback: VoidFunction? = null
        ): Promise<Void>

        // Displays the native touch calibration UX for the display with id as display id. This will show an overlay on the screen with required instructions on how to proceed. The callback will be invoked in case of successful calibration only. If the calibration fails, this will throw an error.¬
        // @return {callback.success}
        @ChromeMinVersion(57)
        @PromiseStyleMinVersion(91)
        abstract fun showNativeTouchCalibration(
            // The display's unique identifier.
            id: String,
            callback: Value1Function<Boolean>? = null
        ): Promise<Boolean>

        // Starts custom touch calibration for a display. This should be called when using a custom UX for collecting calibration data. If another touch calibration is already in progress this will throw an error.
        // @param {String} The display's unique identifier.
        @ChromeMinVersion(57)
        abstract fun startCustomTouchCalibration(id: String)

        // Fired when anything changes to the display configuration.
        abstract val onDisplayChanged: Events.Event<VoidFunction>

        // An enum to tell if the display is detected and used by the system. The display is considered 'inactive', if it is not detected by the system (maybe disconnected, or considered disconnected due to sleep mode, etc). This state is used to keep existing display when the all displays are disconnected, for example.
        @ChromeMinVersion(117)
        enum class ActiveState {
            active,
            inactive,
        }

        data class Bounds(
            var height: Number,
            var left: Number,
            var top: Number,
            var width: Number,
        )

        data class DisplayLayout(
            // The unique identifier of the display.
            var id: String,
            // The offset of the display along the connected edge. 0 indicates that the topmost or leftmost corners are aligned.
            var offset: Number,
            // The unique identifier of the parent display. Empty if this is the root.
            var parentId: String,
            // The layout position of this display relative to the parent. This will be ignored for the root.
            var position: LayoutPosition,
        )

        @ChromeMinVersion(52)
        data class DisplayMode(
            //The display mode device scale factor.
            var deviceScaleFactor: Number,
            // The display mode height in device independent (user visible) pixels.
            var height: Number,
            // The display mode height in native pixels.
            var heightInNativePixels: Number,
            // True if this mode is interlaced, false if not provided.
            @ChromeMinVersion(74)
            var isInterlaced: Boolean?,
            // True if the mode is the display's native mode.
            var isNative: Boolean,
            // True if the display mode is currently selected.
            var isSelected: Boolean,
            // The display mode refresh rate in hertz.
            @ChromeMinVersion(67)
            var refreshRate: Number,
            // The display mode UI scale factor.
            @Deprecated(
                "Deprecated since Chrome 70",
                replaceWith = ReplaceWith("Use displayZoomFactor")
            )
            var uiScale: Number?,
            // The display mode width in device independent (user visible) pixels.
            var width: Number,
            // The display mode width in native pixels.
            var widthInNativePixels: Number,
        )

        data class DisplayProperties(
            // If set, updates the display's logical bounds origin along the x-axis. Applied together with boundsOriginY. Defaults to the current value if not set and boundsOriginY is set. Note that when updating the display origin, some constraints will be applied, so the final bounds origin may be different than the one set. The final bounds can be retrieved using getInfo. The bounds origin cannot be changed on the primary display.
            var boundsOriginX: Number?,
            // If set, updates the display's logical bounds origin along the y-axis. See documentation for boundsOriginX parameter.
            var boundsOriginY: Number?,
            // If set, updates the display mode to the mode matching this value. If other parameters are invalid, this will not be applied. If the display mode is invalid, it will not be applied and an error will be set, but other properties will still be applied.
            @ChromeMinVersion(52)
            var displayMode: DisplayMode?,
            // If set, updates the zoom associated with the display. This zoom performs re-layout and repaint thus resulting in a better quality zoom than just performing a pixel by pixel stretch enlargement.
            @ChromeMinVersion(65)
            var displayZoomFactor: Number?,
            // If set to true, makes the display primary. No-op if set to false. Note: If set, the display is considered primary for all other properties (i.e. isUnified may be set and bounds origin may not).
            var isPrimary: Boolean?,
            // ChromeOS only. If set to true, changes the display mode to unified desktop (see enableUnifiedDesktop for details). If set to false, unified desktop mode will be disabled. This is only valid for the primary display. If provided, mirroringSourceId must not be provided and other properties will be ignored. This is has no effect if not provided.
            @ChromeMinVersion(59)
            var isUnified: Boolean?,
            // ChromeOS only. If set and not empty, enables mirroring for this display only. Otherwise disables mirroring for all displays. This value should indicate the id of the source display to mirror, which must not be the same as the id passed to setDisplayProperties. If set, no other property may be set.
            @ChromeOSOnly
            @Deprecated(
                "Deprecated since Chrome 68",
                replaceWith = ReplaceWith("Use setMirrorMode.")
            )
            var mirroringSourceId: String?,
            // If set, sets the display's overscan insets to the provided values. Note that overscan values may not be negative or larger than a half of the screen's size. Overscan cannot be changed on the internal monitor.
            var overscan: Insets?,
            // If set, updates the display's rotation. Legal values are [0, 90, 180, 270]. The rotation is set clockwise, relative to the display's vertical position.
            var rotation: Number?,
        )

        data class DisplayUnitInfo(
            // Active if the display is detected and used by the system.
            @ChromeMinVersion(117)
            var activeState: ActiveState,
            // A list of zoom factor values that can be set for the display.
            @ChromeMinVersion(67)
            var availableDisplayZoomFactors: List<Number>,
            // The display's logical bounds.
            var bounds: Bounds,
            // The ratio between the display's current and default zoom. For example, value 1 is equivalent to 100% zoom, and value 1.5 is equivalent to 150% zoom.
            @ChromeMinVersion(65)
            var displayZoomFactor: Number,
            // The number of pixels per inch along the x-axis.
            var dpiX: Number,
            // The number of pixels per inch along the y-axis.
            var dpiY: Number,
            // NOTE: This is only available to ChromeOS Kiosk apps and Web UI.
            @ChromeMinVersion(67)
            var edid: Edid?,
            // True if this display has a touch input device associated with it.
            @ChromeMinVersion(57)
            var hasTouchSupport: Boolean,
            // The unique identifier of the display.
            var id: String,
            // True if this display is enabled.
            var isEnabled: Boolean,
            // True if this is the primary display.
            var isPrimary: Boolean,
            // True for all displays when in unified desktop mode. See documentation for enableUnifiedDesktop.
            @ChromeMinVersion(59)
            var isUnified: Boolean,
            // ChromeOS only. Identifiers of the displays to which the source display is being mirrored. Empty if no displays are being mirrored. This will be set to the same value for all displays. This must not include mirroringSourceId.
            @ChromeOSOnly
            @ChromeMinVersion(64)
            var mirroringDestinationIds: List<String>,
            // ChromeOS only. Identifier of the display that is being mirrored if mirroring is enabled, otherwise empty. This will be set for all displays (including the display being mirrored).
            @ChromeOSOnly
            var mirroringSourceId: String,
            // The list of available display modes. The current mode will have isSelected=true. Only available on ChromeOS. Will be set to an empty array on other platforms.
            @ChromeMinVersion(52)
            var modes: List<DisplayMode>,
            // The user-friendly name (e.g. "HP LCD monitor").
            var name: String,
            // The display's insets within its screen's bounds. Currently exposed only on ChromeOS. Will be set to empty insets on other platforms.
            var overscan: Insets,
            // The display's clockwise rotation in degrees relative to the vertical position. Currently exposed only on ChromeOS. Will be set to 0 on other platforms. A value of -1 will be interpreted as auto-rotate when the device is in a physical tablet state.
            var rotation: Number,
            // The usable work area of the display within the display bounds. The work area excludes areas of the display reserved for OS, for example taskbar and launcher.
            var workArea: Bounds,
        )

        @ChromeMinVersion(67)
        data class Edid(
            // 3 character manufacturer code. See Sec. 3.4.1 page 21. Required in v1.4.
            var manufacturerId: String,
            // 2 byte manufacturer-assigned code, Sec. 3.4.2 page 21. Required in v1.4.
            var productId: String,
            // Year of manufacturer, Sec. 3.4.4 page 22. Required in v1.4.
            var yearOfManufacture: Number,
        )

        @ChromeMinVersion(59)
        data class GetInfoFlags(
            // If set to true, only a single DisplayUnitInfo will be returned by getInfo when in unified desktop mode (see enableUnifiedDesktop). Defaults to false.
            var singleUnified: Boolean?,
        )

        data class Insets(
            var bottom: Number,
            var left: Number,
            var right: Number,
            var top: Number,

            )

        // Layout position, i.e. edge of parent that the display is attached to.
        @ChromeMinVersion(53)
        enum class LayoutPosition {
            top,
            bottom,
            left,
            right,
        }

        // Mirror mode, i.e. different ways of how a display is mirrored to other displays.
        @ChromeMinVersion(65)
        enum class MirrorMode {
            // Specifies the default mode (extended or unified desktop).
            off,

            // Specifies that the default source display will be mirrored to all other displays.
            normal,

            // Specifies that the specified source display will be mirrored to the provided destination displays. All other connected displays will be extended.
            mixed
        }

        @ChromeMinVersion(65)
        data class MirrorModeInfo(
            // The ids of the mirroring destination displays. This is only valid for 'mixed'.
            var mirroringDestinationIds: List<String>?,
            // The id of the mirroring source display. This is only valid for 'mixed'.
            var mirroringSourceId: String?,
            // The mirror mode that should be set.
            var mode: MirrorMode,
        )

        @ChromeMinVersion(57)
        data class Point(
            var x: Number,
            var y: Number,
        )

        @ChromeMinVersion(57)
        data class TouchCalibrationPair(
            // The coordinates of the display point.
            var displayPoint: Point,
            // The coordinates of the touch point corresponding to the display point.
            var touchPoint: Point,
        )

        @ChromeMinVersion(57)
        data class TouchCalibrationPairQuad(
            var pair1: TouchCalibrationPair,
            var pair2: TouchCalibrationPair,
            var pair3: TouchCalibrationPair,
            var pair4: TouchCalibrationPair,
        )
    }
    ////////////////////
    // System Memory
    ////////////////////
    /**
     * The `Browser.system.memory` API.
     *
     * Permissions: "system.memory"
     */
    interface Memory {
        // Get physical memory information.
        @PromiseStyleMinVersion(91)
        abstract fun getInfo(callback: Value1Function<MemoryInfo>? = null): Promise<MemoryInfo>
        data class MemoryInfo(
            // The amount of available capacity, in bytes.
            var availableCapacity: Number,
            // The total amount of physical memory capacity, in bytes.
            var capacity: Number,
        )
    }
    ////////////////////
    // System Storage
    ////////////////////
    /**
     * Use the `Browser.system.storage` API to query storage device information and be notified when a removable storage device is attached and detached.
     *
     * Permissions: "system.storage"
     */
    interface Storage {
        // Ejects a removable storage device.
        @PromiseStyleMinVersion(91)
        abstract fun ejectDevice(
            id: String,
            callback: Value1Function<EjectDeviceResultCode>? = null
        ): Promise<EjectDeviceResultCode>

        // Get the available capacity of a specified id storage device. The id is the transient device ID from StorageUnitInfo.
        @PromiseStyleMinVersion(91)
        abstract fun getAvailableCapacity(
            id: String,
            callback: Value1Function<StorageAvailableCapacityInfo>? = null
        ): Promise<StorageAvailableCapacityInfo>

        // Get the storage information from the system. The argument passed to the callback is an array of StorageUnitInfo objects.
        @PromiseStyleMinVersion(91)
        abstract fun getInfo(callback: Value1Function<List<StorageUnitInfo>>? = null): Promise<List<StorageUnitInfo>>

        // Fired when a new removable storage is attached to the system.
        abstract val onAttached: Events.Event<Value1Function<StorageUnitInfo>>

        // Fired when a removable storage is detached from the system.
        // @callback id
        abstract val onDetached: Events.Event<Value1Function<String>>

        enum class EjectDeviceResultCode {
            // The ejection command is successful -- the application can prompt the user to remove the device.
            success,

            // The device is in use by another application. The ejection did not succeed; the user should not remove the device until the other application is done with the device.
            in_use,

            // There is no such device known.
            no_such_device,

            // The ejection command failed.
            failure,
        }

        data class StorageAvailableCapacityInfo(
            // The available capacity of the storage device, in bytes.
            var availableCapacity: Number,
            // A copied id of getAvailableCapacity function parameter id.
            var id: String,
        )

        data class StorageUnitInfo(
            // The total amount of the storage space, in bytes.
            var capacity: Number,
            // The transient ID that uniquely identifies the storage device. This ID will be persistent within the same run of a single application. It will not be a persistent identifier between different runs of an application, or between different applications.
            var id: String,
            // The name of the storage unit.
            var type: StorageUnitType,
        )

        enum class StorageUnitType {
            // The storage has fixed media, e.g. hard disk or SSD.
            fixed,

            // The storage is removable, e.g. USB flash drive.
            removable,

            // The storage type is unknown.
            unknown,
        }
    }
}